Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Image] Implement 'center' and 'repeat' resizeModes #2581

Merged
merged 12 commits into from
Jun 18, 2019

Conversation

marlenecota
Copy link
Contributor

@marlenecota marlenecota commented Jun 6, 2019

#2111

ImageViewManager:

  • Changed Image to ReactImage/Canvas
  • Moved all Image related files to their own folder.

ReactImage:

  • Canvas wrapper to play nice with ReactImageBrush
  • Overrides ArrangeOverride to provide ReactImageBrush the available size (needed for 'center' and 'repeat'

ReactImageBrush:

  • XamlCompositionBrushBase that switches source brush based on resizeMode
  • Uses CompositionEffectBrush for 'repeat' resizeMode

BorderEffect:

  • Header-only implementation of Win2D-like BorderEffect (used in Windows::UI::Composition APIs)
  • Includes EffectBase as we will probably need to add more Effects in the future (e.g. Blur)
Microsoft Reviewers: Open in CodeFlow

@marlenecota marlenecota requested a review from a team as a code owner June 6, 2019 19:51
@ghost ghost added the vnext label Jun 6, 2019
@marlenecota marlenecota added this to the vNext Milestone 2 milestone Jun 6, 2019
Copy link
Member

@ahimberg ahimberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕐

@ghost ghost added the Needs: Author Feedback The issue/PR needs activity from its author (label drives bot activity) label Jun 7, 2019
{
bool effectToSurfaceBrushSwitch{
ResizeMode() != ResizeMode::Repeat &&
!CompositionBrush().try_as<winrt::CompositionSurfaceBrush>() };
Copy link
Contributor

@kmelmon kmelmon Jun 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!CompositionBrush().try_aswinrt::CompositionSurfaceBrush() [](start = 8, length = 60)

This check feels a bit awkward - we're looking to see if we have an effect brush set, yes? In this case can you check for a non-null m_effectBrush instead? Alternatively, consider refactoring this into a "HasEffectBrush()" helper function #Closed

Copy link
Contributor Author

@marlenecota marlenecota Jun 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm caching the effect brush in case they have some kind of mechanism to switch an image's resizeMode at runtime, so we can't just check to see if it's not null. What I want to know is if the current composition brush is not a CompositionSurfaceBrush (because that's when we would want to switch brushes). I've added a "UsingSurfaceBrush()" helper function. #Closed

ResizeMode() != ResizeMode::Repeat &&
!CompositionBrush().try_as<winrt::CompositionSurfaceBrush>() };

bool surfaceToEffectBrushSwitch{ ResizeMode() == ResizeMode::Repeat };
Copy link
Contributor

@kmelmon kmelmon Jun 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bool surfaceToEffectBrushSwitch{ ResizeMode() == ResizeMode::Repeat }; [](start = 6, length = 70)

This seems to be missing a bit of logic (I think it should also check for a null m_effectBrush). #Closed

Copy link
Contributor Author

@marlenecota marlenecota Jun 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The effect brush is created and/or retrieved just before the call to this method and the GetOrCreateEffectBrush call is also gated by the same logic (ResizeMode == Repeat).

All other modes use the SurfaceBrush, so we always have to switch brushes if ResizeMode has been set to Repeat. #Resolved

Copy link
Contributor

@kmelmon kmelmon Jun 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation. Reading through this a bit more carefully, I see where I got confused - this function isn't really checking to see if we need to switch brushes as it might already be set to the appropriate brush. It looks like you could remove ShouldSwitchCompositionBrush() altogether, and set the CompositionBrush to what you've already got in compositionBrush. As it stands the code is somewhat confusing.


In reply to: 293640055 [](ancestors = 293640055)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does check if we need to switch brushes. It's basically just preventing an unnecessary CompositionBrush set when we are switching between two resizeModes that use a CompositionSurfaceBrush (center, contain, cover, stretch). In those cases all we need to do is update CompositionSurfaceBrush.Stretch which is what we do right after we get the SurfaceBrush.

I think the most human way of expressing this is in the negative (i.e. when do we NOT want to switch brushes), so maybe this is more readable?

bool ReactImageBrush::ShouldSwitchCompositionBrush()
{
// The only scenario where we do not want to switch brushes is if:
// 1. We're not switching to the EffectBrush (Repeat is the only resizeMode that uses the EffectBrush) and
// 2. We're already using the SurfaceBrush
return !(ResizeMode() != ResizeMode::Repeat && UsingSurfaceBrush())
}


In reply to: 294010205 [](ancestors = 294010205,293640055)

Copy link
Contributor

@kmelmon kmelmon Jun 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this example run-through will help illustrate the point I'm trying to make:

  1. App sets ResizeMode to Repeat => ShouldSwitchCompositionBrush returns true, because ResizeMode() == Repeat.
  2. A little bit later, the size of the element changes and we set the AvailableSize. => ShouldSwitchCompositionBrush again returns true, even though we already have the effect brush set.
    I would have expected the function to only return true if we actually need to set a new brush into CompositionBrush().

If I'm reading the code correctly, everything that leads up to the "should switch brushes" check is computing the brush that we should set. Assuming I've got this correct, why can't you just query the current CompositionBrush() and compare to the one you're about to set, and only set if they are different? #Resolved

@ghost ghost removed the Needs: Author Feedback The issue/PR needs activity from its author (label drives bot activity) label Jun 14, 2019
Copy link
Contributor

@kmelmon kmelmon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

ImageSource source{ reactImage->Source() };

EmitImageEvent(m_wkReactInstance.lock(), reactImage.as<winrt::Canvas>(), succeeded ? "topLoad" : "topError", source);
EmitImageEvent(m_wkReactInstance.lock(), reactImage.as<winrt::Canvas>(), "topLoadEnd", source);
Copy link
Member

@ahimberg ahimberg Jun 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as mentioned over chat, we want to change these to fire only when subscribed to, which will require having a shadownode to store if onLoad/etc have been set. #Resolved

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh i thought maybe these were firing more than before your change (for non-http) but that doesn't appear to be the case, future fix...


In reply to: 294093989 [](ancestors = 294093989)

Copy link
Member

@ahimberg ahimberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

};

HRESULT GetNamedPropertyMappingImpl(
_In_count_(mappingCount) const NamedProperty* namedProperties,
Copy link
Member

@chrisglein chrisglein Jun 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should that be _In_count(namedPropertyCount)? #Resolved

#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.UI.h>

#define CATCH_RETURN \
Copy link
Member

@chrisglein chrisglein Jun 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this (and probably the DECLARE macros below?) should be in a separate header. #Resolved

return image;
auto reactImage{ ReactImage::Create() };

reactImage->OnLoadEnd([=](const auto&, const bool& succeeded)
Copy link
Member

@chrisglein chrisglein Jun 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of good reasons to avoid default lambda captures entirely. Consider making this an explicit capture of [this, reactImage] (tag is unused?)
Check out F.54, for example. #Resolved

}
}
catch (winrt::hresult_error const&)
{
Copy link
Member

@chrisglein chrisglein Jun 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this fire the load end event?
(like above when the memory stream fails?) #Resolved

Copy link
Contributor

@stecrain stecrain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking forward to trying out these changes
🚀

}

// Only switch CompositionBrush if we are switching to/from ResizeMode::Repeat
if (ShouldSwitchCompositionBrush())
Copy link
Member

@chrisglein chrisglein Jun 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this check be made before creating surfaceBrush and compositionBrush? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a bad name. The code above determines the correct brush we need to use. This should just check to see if it is different than what we're currently using and set it if that's the case.


In reply to: 294561221 [](ancestors = 294561221)

@marlenecota marlenecota merged commit f750896 into microsoft:master Jun 18, 2019
@marlenecota marlenecota deleted the image-bordereffect branch September 8, 2020 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants